package task

import (
	"codedef"
	"github.com/garyburd/redigo/redis"
	"log"
	"oceanserv"
	"rhelper"
	"strconv"
	"strings"
)

func loadTask(taskId string) (*Task, int) {
	conn := rhelper.Pool().Get()
	defer conn.Close()

	rr, err := redis.Strings(conn.Do("HMGET", rhelper.TaskHash+taskId, "type", "perbatch", "duration"))
	if err != nil {
		log.Println("loadTask failed:", err)
		return nil, codedef.ERR_DATABASE
	}

	var errc int = 0
	t := &Task{}
	t.id = taskId
	t.ttype = rr[0]
	t.perbatch, _ = strconv.Atoi(rr[1])
	t.duration, _ = strconv.Atoi(rr[2])

	switch rr[0] {
	case "vv":
		t, errc = parseVVTask(conn, taskId, t)
		break
	default:
		log.Println("loadTask failed, unsupported type:", rr[0])
		t = nil
		break
	}

	return t, errc
}

func parseVVTask(conn redis.Conn, taskId string, t *Task) (*Task, int) {
	var errc int = 0
	t, errc = loadPumpsOfTask(conn, t)
	if t == nil {
		return nil, errc
	}

	t, errc = loadAlwaysOpenValvesOfTask(conn, t)
	if t == nil {
		return nil, errc
	}

	t, errc = loadAlwaysCloseValvesOfTask(conn, t)
	if t == nil {
		return nil, errc
	}

	return loadVavlesOfTask(conn, t)
}

func loadPumpsOfTask(conn redis.Conn, t *Task) (*Task, int) {
	taskId := t.id
	var errc int = 0
	cc, errc := loadTaskControllers(conn, taskId, "pump")
	if cc == nil {
		return t, errc
	}

	t.pumpGroup = toTControllerGroup(cc)
	return t, errc
}

func loadAlwaysOpenValvesOfTask(conn redis.Conn, t *Task) (*Task, int) {
	taskId := t.id
	var errc int = 0
	cc, errc := loadTaskControllers(conn, taskId, "ao")
	if cc == nil {
		return t, errc
	}

	t.valveAlwaysOpen = toTControllerGroup(cc)
	return t, errc
}

func loadAlwaysCloseValvesOfTask(conn redis.Conn, t *Task) (*Task, int) {
	taskId := t.id
	var errc int = 0
	cc, errc := loadTaskControllers(conn, taskId, "ac")
	if cc == nil {
		return t, errc
	}

	t.valveAlwaysClose = toTControllerGroup(cc)
	return t, errc
}

func loadVavlesOfTask(conn redis.Conn, t *Task) (*Task, int) {
	taskId := t.id
	var errc int = 0
	cc, errc := loadTaskControllers(conn, taskId, "vv")
	if cc == nil {
		log.Println("loadVavlesOfTask failed, no controller on vv field, task id:", taskId)
		return nil, errc
	}

	perbatch := t.perbatch
	vglength := len(cc) / perbatch
	if 0 != (len(cc) % perbatch) {
		vglength += 1
	}

	vgs := make([]*TControllerGroup, vglength)
	var i int = 0 // controller index of cc
	var k int = 0 // group index of vgs
	for i < len(cc) {
		var j int = 0 // j is controller index of a group
		for j < perbatch && i < len(cc) {
			vg := vgs[k]
			if vg == nil {
				vg = &TControllerGroup{}
				vgs[k] = vg
				if len(cc)-i >= perbatch {
					vg.controllers = make([]*TController, perbatch)
				} else {
					vg.controllers = make([]*TController, len(cc)-i)
				}
			}

			tc := &TController{}
			tc.gwId = cc[i].GetGWId()
			tc.id = cc[i].GetId()

			vg.controllers[j] = tc

			j++ // move forward
			i++ // move forward
		}

		k++ // next group
	}

	t.valveGroups = vgs
	return t, errc
}

func loadTaskControllers(conn redis.Conn, taskId string, field string) ([]*oceanserv.Controller, int) {
	log.Printf("loadTaskController, taskId:%s, field:%s\n", taskId, field)
	ids, err := redis.String(conn.Do("HGET", rhelper.TaskHash+taskId, field))
	if err != nil {
		log.Println("loadTaskControllers failed:", err)
		return nil, codedef.ERR_DATABASE
	}

	if ids == "" {
		log.Println("loadTaskControllers, no values for:", field)
		return nil, codedef.ERR_DATABASE
	}

	idsArray := strings.Split(ids, ",")

	var index int = 0
	cc := make([]*oceanserv.Controller, len(idsArray))
	// now just use a simple way to load, will change to MULTI later
	for _, id := range idsArray {
		gwId, err := redis.String(conn.Do("HGET", rhelper.ControllerHash+id, "gwId"))
		if err != nil {
			log.Println("loadTaskControllers failed:", err)
			return nil, codedef.ERR_DATABASE
		}

		idi, _ := strconv.Atoi(id)
		c := oceanserv.GetController(gwId, int32(idi))
		if c == nil {
			log.Println("loadTaskControllers failed: controller is offline, id:", id)
			return nil, codedef.ERR_TASK_CONTROLLER_NOT_VALID
		}

		cc[index] = c
		index++
	}

	return cc, 0
}

func toTControllerGroup(cc []*oceanserv.Controller) *TControllerGroup {
	g := &TControllerGroup{}
	g.controllers = make([]*TController, len(cc))

	for i, c := range cc {
		tc := &TController{}
		tc.gwId = c.GetGWId()
		tc.id = c.GetId()

		g.controllers[i] = tc
	}

	return g
}
